﻿using Microsoft.EntityFrameworkCore;
using FrameworkCore.Models;
using FrameworkCore.Migrations.Data;
using AutoMapper.QueryableExtensions;
using AutoMapper;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;

namespace FrameworkCore.Extensions;

public static class QueryableExtensions
{
    /// <summary>
    /// 为分页结果集提供有序可查询数据的扩展方法。
    /// </summary>
    /// <remarks>
    /// 该方法将给定的规范应用于查询，对结果进行分页，并将它们投影到所需的结果类型。
    /// </remarks>
    /// <typeparam name="T">查询中实体的源类型</typeparam>
    /// <typeparam name="TResult">实体应投影到的目标类型</typeparam>
    /// <param name="query">要投影和分页的原始有序查询</param>
    /// <param name="spec">在投影和分页之前应用于查询的规范</param>
    /// <param name="pageNumber">分页结果的所需页码</param>
    /// <param name="pageSize">分页结果中每页的项目数</param>
    /// <param name="configuration">投影的配置</param>
    /// <param name="cancellationToken">用于取消操作的可选取消令牌</param>
    /// <returns>分页和投影的数据</returns>
    public static async Task<PaginatedData<TResult>> ProjectToPaginatedDataAsync<T, TResult>(this IOrderedQueryable<T> query, int pageNumber, int pageSize, IConfigurationProvider configuration, CancellationToken cancellationToken = default) where T : class, IEntity
    {
        var count =await query.CountAsync();
        var data = await query.AsNoTracking().Skip((pageNumber - 1) * pageSize).Take(pageSize)
            .ProjectTo<TResult>(configuration)
            .ToListAsync(cancellationToken);
        return new PaginatedData<TResult>(data, count, pageNumber, pageSize);
    }

    /// <summary>
    /// 如果指定的条件为真，则对查询应用过滤器。
    /// </summary>
    /// <typeparam name="T">查询序列中元素的类型。</typeparam>
    /// <param name="query">要过滤的查询序列。</param>
    /// <param name="condition">一个布尔值，决定是否应用过滤器。</param>
    /// <param name="predicate">一个表达式树，定义了过滤条件。</param>
    /// <returns>如果条件为真，则返回经过过滤的 IQueryable<T>；否则，返回原始的 IQueryable<T>。</returns>
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool condition, Expression<Func<T, bool>> predicate)
    {
        if (condition)
        {
            return query.Where(predicate);
        }

        return query;
    }
}